package com.app.oasystem.service.impl;

import com.app.oasystem.constant.StaticParam;
import com.app.oasystem.dto.ActionResult;
import com.app.oasystem.entity.User;
import com.app.oasystem.mapper.UserMapper;
import com.app.oasystem.utils.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;

import static com.app.oasystem.constant.LimitLoginEnum.*;
import static com.app.oasystem.constant.StaticParam.SESSIONKEY_LOGIN_INFO;

/**
 * @author zhangbaobing
 * @Description TODO
 * @data 2021/04/20
 */
@Service
@Slf4j
public class LoginService {
    @Resource
    UserMapper userMapper;

    /**
     * 用户登录 a. 基础输入项校验; b. 校验当前登入用户是否和session中现有用户一致; c. 新用户密码校验登入，保存相关信息;
     *
     * @param input
     * @param request
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Object loginSystem(HashMap<String, Object> input, HttpServletRequest request, HttpServletResponse reponse) {
        String username = String.valueOf(input.get("username")).trim();
        String password = String.valueOf(input.get("password")).trim();
        password = PwdUtil.decodes(password);
        String veryCode = String.valueOf(input.get("veryCode")).trim();

        if (!StringUtil.hasText(veryCode)) {
            return new ActionResult(false, "验证码不能为空！", true);
        }
        if (!StringUtil.hasText(username)) {
            return new ActionResult(false, "登录名称不能为空！", true);
        }
        if (!StringUtil.hasText(password)) {
            return new ActionResult(false, "登录密码不能为空！", true);
        }

        // 从session里取得验证码信息
        String identifyingCode = (String) request.getSession().getAttribute(StaticParam.SESSIONKEY_IDENTIFYING_CODE);

        //置空验证码的session，一次有效，防止被爆破
        request.getSession().setAttribute(StaticParam.SESSIONKEY_IDENTIFYING_CODE, "");

        //判断验证码
        if (StringUtil.hasText(identifyingCode)) {
            if (!identifyingCode.equals(veryCode)) {
                Object obj = this.loginFailure(username);
                if (null != obj) {
                    return obj;
                }
                return new ActionResult(false, "验证码错误！", true);
            }
        } else {
            return new ActionResult(false, "非法登陆！", true);
        }

        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));

        // 校验用户密码
        if (user.getPassword().equals(password)) {
            log.info("用户登录：" + username);
            Object obj = this.loginSuccess(username);
            if (null != obj) {
                return obj;
            }
            request.getSession().setAttribute(StaticParam.SESSIONKEY_LOGIN_INFO, user.getUsername());
            return new ActionResult(true, "登录成功！", user.getId());
        } else {
            Object obj = this.loginFailure(username);
            if (null != obj) {
                return obj;
            }
            return new ActionResult(false, "密码错误！");
        }

    }


    /**
     * 登录失败
     *
     * @param dummy 用户名
     *              两种情况
     *              1.密码错误的情况
     *              2.验证码错误的情况
     */
    public Object loginFailure(Object dummy) {
        HashMap<String, Object> map = this.loginCommon(dummy);
        User userStatus = new User();
        userStatus.setUsername(dummy.toString());
        if (null != map && map.size() != 0) {
            String loginCount = map.get("loginCount").toString();
            long diff = (long) map.get("diff");

            if (Integer.parseInt(loginCount) < MAX_COUNT) {
                String failureCount = "" + (Integer.parseInt(loginCount) + 1);
                userStatus.setLoginCount(failureCount);
                userStatus.setLoginTime(new Date());
                userMapper.update(userStatus,new UpdateWrapper<User>().eq("username",dummy.toString()));
            }

            if (StringUtil.hasText(loginCount)) {
                if (Integer.parseInt(loginCount) == MAX_COUNT && diff <= LIMIT_TIME) {
                    return new ActionResult(false, "连续登陆失败，已限制登陆！", true);
                }
            }
        } else {
            userStatus.setLoginCount("1");
            log.info("最近登录时间{[" + DateUtils.getDateTime("yyyy-MM-dd HH:mm:ss") + "]}");
            userStatus.setLoginTime(new Date());
            userMapper.update(userStatus,new UpdateWrapper<User>().eq("username",dummy.toString()));
        }
        return null;
    }

    /**
     * 登录成功后登录次数和登录时间状态
     * 三种情况
     * 1 已登录失败5次，限制登录时间在一小时内
     * 2 已登录失败5次，限制登录时间在一小时外
     * 3 已登录失败少于5次
     * 更新登录次数 为 0 ，登录时间为当前时间
     *
     * @param dummy 用户名
     */
    public Object loginSuccess(Object dummy) {
        HashMap<String, Object> map = this.loginCommon(dummy);
        if (null != map) {
            String loginCount = map.get("loginCount").toString();
            long diff = (long) map.get("diff");

            if (Integer.parseInt(loginCount) == MAX_COUNT && diff <= LIMIT_TIME) {
                return new ActionResult(false, "连续登陆失败，已限制登陆！", true);
            }

            if ((Integer.parseInt(loginCount) <= MAX_COUNT && Integer.parseInt(loginCount) > DEFAULT_COUNT) || diff > LIMIT_TIME) {
                User userStatus = new User();
                userStatus.setUsername(dummy.toString());
                userStatus.setLoginCount(String.valueOf(DEFAULT_COUNT));
                userStatus.setLoginTime(new Date());
                userMapper.update(userStatus,new UpdateWrapper<User>().eq("username",dummy));
            }
        }
        return null;
    }

    /**
     * 登录成功后和登陆失败 登录次数和登录时间状态 的通用前置代码
     *
     * @param dummy 用户名
     */
    private HashMap<String, Object> loginCommon(Object dummy) {
        HashMap map = new HashMap();
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username",dummy));
        String loginCount = user.getLoginCount();
        //  rTime 最近登录时间
        Date rTime = user.getLoginTime();
        // eTime 当前时间
        Date eTime = DateUtils.parseDate(DateUtils.getDateTime(DATE_FORMAT), DATE_FORMAT);
        if (StringUtil.hasText(loginCount) && null != rTime) {
            long diff = DateUtils.dateChange(rTime, eTime);
            map.put("loginCount", loginCount);
            map.put("diff", diff);
        }
        return map;
    }
}
